use petgraph::graph::{UnGraph, NodeIndex};
use std::collections::HashMap;
use chrono::NaiveDate;

#[derive(Debug, Clone)]
struct Scrap {
    scrap_quantity: u32,      // 报废数
    system_code: String,      // 系统码（可以重复）
    scrap_order: String,      // 报废单号
    scrap_date: NaiveDate,    // 报废时间
}

#[derive(Debug, Clone)]
struct Material {
    material_code: String,    // 物料编码
    material_name: String,    // 物料名称
}

#[derive(Debug, Clone)]
enum NodeData {
    Scrap(Scrap),
    Material(Material),
}

struct ScrapGraph {
    graph: UnGraph<NodeData, ()>,
    material_nodes: HashMap<String, NodeIndex>, // 物料编码 -> 节点索引
    system_code_nodes: HashMap<String, Vec<NodeIndex>>, // 系统码 -> 节点索引列表（可重复）
}

impl ScrapGraph {
    fn new() -> Self {
        Self {
            graph: UnGraph::new_undirected(),
            material_nodes: HashMap::new(),
            system_code_nodes: HashMap::new(),
        }
    }
    
    // 添加报废记录
    fn add_scrap(&mut self, scrap: Scrap) -> NodeIndex {
        let node = self.graph.add_node(NodeData::Scrap(scrap.clone()));
        
        // 记录系统码对应的节点（允许多个节点有相同系统码）
        self.system_code_nodes
            .entry(scrap.system_code.clone())
            .or_insert_with(Vec::new)
            .push(node);
            
        node
    }
    
    // 添加物料
    fn add_material(&mut self, material: Material) -> NodeIndex {
        let material_code = material.material_code.clone();
        let node = self.graph.add_node(NodeData::Material(material));
        
        // 物料编码应该是唯一的
        self.material_nodes.insert(material_code, node);
        node
    }
    
    // 建立系统码和物料编码的关联
    fn link(&mut self, system_code: &str, material_code: &str) {
        if let (Some(scrap_nodes), Some(&material_node)) = (
            self.system_code_nodes.get(system_code),
            self.material_nodes.get(material_code)
        ) {
            for &scrap_node in scrap_nodes {
                self.graph.add_edge(scrap_node, material_node, ());
            }
        }
    }
    
    // 查询：根据物料编码找到所有相关的报废记录
    fn get_scrap_for_matcode(&self, material_code: &str) -> Vec<&Scrap> {
        let mut scraps = Vec::new();
        
        if let Some(&material_node) = self.material_nodes.get(material_code) {
            for neighbor in self.graph.neighbors(material_node) {
                if let NodeData::Scrap(scrap) = &self.graph[neighbor] {
                    scraps.push(scrap);
                }
            }
        }
        
        scraps
    }
    
    // 查询：根据系统码找到对应的物料
    fn get_materials_for_system_code(&self, system_code: &str) -> Vec<&Material> {
        let mut materials = Vec::new();
        
        if let Some(scrap_nodes) = self.system_code_nodes.get(system_code) {
            for &scrap_node in scrap_nodes {
                for neighbor in self.graph.neighbors(scrap_node) {
                    if let NodeData::Material(material) = &self.graph[neighbor] {
                        materials.push(material);
                    }
                }
            }
        }
        
        materials
    }
    
    // 统计物料的总报废数量
    fn get_total_scrap_for_material(&self, material_code: &str) -> u32 {
        self.get_scrap_for_matcode(material_code)
            .iter()
            .map(|scrap| scrap.scrap_quantity)
            .sum()
    }
    
    // 查找有共同物料的系统码
    fn find_related_system_codes(&self, material_code: &str) -> Vec<String> {
        let mut system_codes = Vec::new();
        
        for scrap in self.get_scrap_for_matcode(material_code) {
            system_codes.push(scrap.system_code.clone());
        }
        
        system_codes.sort();
        system_codes.dedup();
        system_codes
    }
    
    // 显示图结构（调试用）
    fn print_graph(&self) {
        println!("=== 图结构 ===");
        for node in self.graph.node_indices() {
            match &self.graph[node] {
                NodeData::Scrap(scrap) => {
                    println!("报废节点: {} (单号: {})", scrap.system_code, scrap.scrap_order);
                    for neighbor in self.graph.neighbors(node) {
                        if let NodeData::Material(mat) = &self.graph[neighbor] {
                            println!("  -> 连接到物料: {}", mat.material_code);
                        }
                    }
                }
                NodeData::Material(material) => {
                    println!("物料节点: {} ({})", material.material_code, material.material_name);
                }
            }
        }
    }
}

fn main() {
    let mut graph = ScrapGraph::new();

    // 添加报废数据（系统码可以重复）
    graph.add_scrap(Scrap {
        scrap_quantity: 100,
        system_code: "SYS001".to_string(),
        scrap_order: "SO001".to_string(),
        scrap_date: NaiveDate::from_ymd_opt(2024, 1, 15).unwrap(),
    });

    graph.add_scrap(Scrap {
        scrap_quantity: 555,
        system_code: "SYS001".to_string(),
        scrap_order: "SO001".to_string(),
        scrap_date: NaiveDate::from_ymd_opt(2024, 1, 15).unwrap(),
    });
    
    graph.add_scrap(Scrap {
        scrap_quantity: 50,
        system_code: "SYS001".to_string(), // 相同系统码
        scrap_order: "SO002".to_string(),
        scrap_date: NaiveDate::from_ymd_opt(2024, 1, 16).unwrap(),
    });
    
    graph.add_scrap(Scrap {
        scrap_quantity: 200,
        system_code: "SYS002".to_string(),
        scrap_order: "SO003".to_string(),
        scrap_date: NaiveDate::from_ymd_opt(2024, 1, 17).unwrap(),
    });

    // 添加物料数据
    graph.add_material(Material {
        material_code: "MAT001".to_string(),
        material_name: "螺丝".to_string(),
    });
    
    graph.add_material(Material {
        material_code: "MAT002".to_string(),
        material_name: "螺母".to_string(),
    });
    
    graph.add_material(Material {
        material_code: "MAT003".to_string(),
        material_name: "垫片".to_string(),
    });

     graph.add_material(Material {
        material_code: "SYS001".to_string(),
        material_name: "螺丝".to_string(),
    });

    // 建立关系
    graph.link("SYS001", "MAT001");
    graph.link("SYS001", "SYS001");
    graph.link("SYS001", "MAT002");
    graph.link("SYS002", "MAT001");
    graph.link("SYS002", "MAT003");

    // 查询：根据物料编码找报废记录
    println!("=== 物料 MAT001 的报废记录 ===");
    let scraps = graph.get_scrap_for_matcode("MAT001");
    for scrap in scraps {
        println!("系统码: {}, 报废单号: {}, 数量: {}, 日期: {}", 
                 scrap.system_code, scrap.scrap_order, scrap.scrap_quantity, scrap.scrap_date);
    }

    // 查询：根据系统码找物料
    println!("\n=== 系统码 SYS001 使用的物料 ===");
    let materials = graph.get_materials_for_system_code("SYS001");
    for material in materials {
        println!("物料编码: {}, 物料名称: {}", material.material_code, material.material_name);
    }

    // 统计物料总报废量
    println!("\n=== 物料报废统计 ===");
    println!("物料 MAT001 总报废量: {}", graph.get_total_scrap_for_material("MAT001"));
    println!("物料 MAT002 总报废量: {}", graph.get_total_scrap_for_material("MAT002"));
    println!("物料 SYS001 总报废量: {}", graph.get_total_scrap_for_material("SYS001"));

    // 查找相关系统码
    println!("\n=== 与物料 MAT001 相关的系统码 ===");
    let related_systems = graph.find_related_system_codes("MAT001");
    for system in related_systems {
        println!("系统码: {}", system);
    }

    // 显示图结构
    println!("\n=== 图结构展示 ===");
    graph.print_graph();
}